package com.microframework.boot.auth.controller;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.jfinal.kit.StrKit;
import com.microframework.base.core.redis.service.RedisService;
import com.microframework.base.core.security.constants.SecurityConstants;
import com.microframework.base.core.security.model.AuthResponse;
import com.microframework.base.core.security.model.LoginRequest;
import com.microframework.base.core.security.model.RefreshRequest;
import com.microframework.base.core.security.token.TokenParser;
import com.microframework.base.core.util.EncryptUtil;
import com.microframework.base.web.resp.R;
import com.microframework.boot.system.model.domain.User;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;


@Slf4j
@RestController
@RequestMapping("/auth")
@Tag(name = "认证管理", description = "认证管理相关接口")
public class AuthController {
	
	@Autowired
	private DefaultKaptcha kaptcha;

	@Autowired
	private RedisService redisService;
	
	@Autowired
	private TokenParser tokenParser;
	
	/**
	 * 生成验证码 等保要求：提供验证码功能，防止暴力破解
	 */
	@Operation(summary = "获取验证码")
	@GetMapping("/captcha")
	public void captcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
		// 生成验证码文本
		String code = kaptcha.createText();

		// 生成唯一标识
		String captchaKey = UUID.randomUUID().toString();

		// 存储验证码到Redis，有效期5分钟
		redisService.setCacheObject("captcha:" + captchaKey, code, 5L, TimeUnit.MINUTES);

		// 设置验证码标识到Cookie
		response.addCookie(new jakarta.servlet.http.Cookie("captchaKey", captchaKey));

		// 根据文本生成验证码图片
		BufferedImage image = kaptcha.createImage(code);

		// 输出验证码图片
		response.setContentType("image/jpeg");
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		ImageIO.write(image, "jpg", response.getOutputStream());
		response.getOutputStream().flush();
	}
	
	/**
	 * 验证验证码
	 */
	@Operation(summary = "验证验证码")
	@PostMapping("/captcha/verify")
	@ResponseBody
	public R<Void> verifyCaptcha(String code, String captchaKey) {
		// 从Redis获取验证码
		String storedCode = redisService.getCacheObject("captcha:" + captchaKey);

		// 验证码不存在或已过期
		if (storedCode == null) {
			return R.fail("验证码已过期");
		}

		// 验证码错误
		if (!storedCode.equalsIgnoreCase(code)) {
			return R.fail("验证码错误");
		}

		// 验证通过后删除验证码
		redisService.deleteObject("captcha:" + captchaKey);

		return R.ok();
	}
	
	@Operation(summary = "登录")
	@Parameters({ @Parameter(name = "request", description = "登录信息", required = true) })
	@PostMapping("/login")
	public R<AuthResponse> login(@RequestBody LoginRequest request) {
		
		try {
			if(StrKit.isBlank(request.getUsername()) || StrKit.isBlank(request.getPassword())) {
				return R.fail("账号或密码为空.");
			}
			
			String username = EncryptUtil.rsaDecrypt(request.getUsername(), SecurityConstants.PRIVATE_KEY);
			String password = EncryptUtil.rsaDecrypt(request.getPassword(), SecurityConstants.PRIVATE_KEY);
			
			
			User user=User.dao.findFirst("select * from "+User.TABLE_NAME+" where username=?",username);
			if(user==null) {
				return R.fail("账号有误.");
			}
			
			if(StrKit.equals("-1", user.getStatus())) {
				return R.fail("账号已注销.");
			}
			
			if(StrKit.equals("1", user.getStatus())) {
				return R.fail("账号已锁定.");
			}
			
			if(user.getError()>=5) {
				return R.fail("尝试账号密码次数过多，请联系管理员解锁或24小时后再试.");
			}
			
			if(!EncryptUtil.verifyPassword(password, user.getPassword())) {
				new User().setId(user.getId()).setError(user.getError()+1).update();
				return R.fail("密码有误.");
			}
			
			new User().setId(user.getId()).setError(0).update();
			
			// 2. 生成双Token
			String accessToken = tokenParser.generateAccessToken(user.getId());
			String refreshToken = tokenParser.generateRefreshToken(user.getId());
			
			// 3. 存储Token（Redis）
			redisService.setCacheObject(accessToken, user.getId(), tokenParser.getAccessTokenExpiration(), TimeUnit.MILLISECONDS);
			redisService.setCacheObject(refreshToken, user.getId(), tokenParser.getRefreshTokenExpiration(), TimeUnit.MILLISECONDS);
			
		    return R.ok(new AuthResponse(accessToken,refreshToken) );
		}catch (Exception e) {
			return R.fail(e.getMessage());
		}
		
		
	}
	
	@Operation(summary = "刷新令牌")
    @PostMapping("/refresh")
    public R<?> refresh(@RequestBody RefreshRequest request) {
		System.out.println("--------------------------刷新令牌------------------------------");
        String refreshToken = request.getRefreshToken();
        
        if(!tokenParser.validateToken(refreshToken)) {
        	throw new RuntimeException("无效的刷新令牌");
        }
       
        String userId = tokenParser.getUserIdFromToken(refreshToken);
        
		// 2. 生成双Token
		String newAccessToken = tokenParser.generateAccessToken(userId);
		String newRefreshToken = tokenParser.generateRefreshToken(userId);
		
		// 3. 存储Token（Redis）
		redisService.setCacheObject(newAccessToken, userId, tokenParser.getAccessTokenExpiration(), TimeUnit.MILLISECONDS);
		redisService.setCacheObject(newRefreshToken, userId, tokenParser.getRefreshTokenExpiration(), TimeUnit.MILLISECONDS);
        
        return R.ok(new AuthResponse(newAccessToken, newRefreshToken));
    }
	
	@Operation(summary = "登出")
    @PostMapping("/logout")
    public R<Void> logout(@RequestHeader("Authorization") String authHeader) {
        String token = authHeader.substring(7);
        redisService.deleteObject(token);
        return R.ok();
    }

}
